using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.ServiceModel;
using System.Threading;
using AutoMapper;
using Core;
using IglooCoder.Commons.WcfNhibernate;
using Infrastucture;
using WcfService1.DTO;
using Omu.ValueInjecter;

namespace WcfService1
{
    // NOTE: You can use the "Rename" command on the "Refactor" SalesOrder to change the class name "SalesOrderServices" in code, svc and config file together.
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    [NHibernateContext]
    public class SalesOrderServices : ISalesOrderServices
    {
        private readonly SalesOrderRepository SalesOrderRepository;
        private readonly WcfSessionStorage _Session;
        private readonly PreSalesOrderRepository _preSalesOrderRepository;
        private InventoryRepository InventoryRepository;
        private ItemRepository ItemRepository;
        private SubGroupRepository SubGroupRepository;
        private SpkRepository _SpkRepository;
        private SalesInvoiceRepository SIRepository;
        private DeliveryOrderRepository DORepository;

        public SalesOrderServices()
        {
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
            _Session = new WcfSessionStorage();
            SalesOrderRepository = new SalesOrderRepository(_Session);
            ItemRepository = new ItemRepository(_Session);
            SubGroupRepository = new SubGroupRepository(_Session);
            InventoryRepository = new InventoryRepository(_Session);
            _preSalesOrderRepository = new PreSalesOrderRepository(_Session);
            _SpkRepository = new SpkRepository(_Session);
            SIRepository = new SalesInvoiceRepository(_Session);
            DORepository = new DeliveryOrderRepository(_Session);
        }

        #region ISalesOrderServices Members

        public List<SalesOrderDTO> GetList(int page, out long recordCount, string sortProperty = null,
                                           string sortType = "ASC")
        {
            var SalesOrders = new List<SalesOrder>();
            var Results = new List<SalesOrderDTO>();

            if (string.IsNullOrEmpty(sortProperty))
            {
                SalesOrders = SalesOrderRepository.GetDataPaged(page, 30, "SODate", "DESC").ToList();
            }
            else
            {
                SalesOrders = SalesOrderRepository.GetDataPaged(page, 30, sortProperty, sortType).ToList();
            }

            recordCount = SalesOrderRepository.RecordCount;

            SalesOrders.ForEach(x =>
                                    {
                                        SalesOrderDTO salesOrderDto = (SalesOrderDTO) new SalesOrderDTO().InjectFrom(x);
                                        salesOrderDto.Currency = new CurrencyDTO(){CurrencyCode = x.CurrencyCode};
                                        salesOrderDto.Status = (Status) x.Status;
                                        Results.Add(salesOrderDto);
                                    }
                );

            return Results;
        }

        public bool Save(SalesOrderDTO SalesOrderDTO)
        {
            bool res;
            try
            {
                SalesOrderRepository.ExecuteTransactionNative(() =>
                                                                  {
                                                                      SalesOrder SalesOrder = SalesOrderRepository.GetDataOne(x => x.SONo == SalesOrderDTO.SONo);
                                                                      if (SalesOrder == null)
                                                                      {
                                                                          SalesOrder = new SalesOrder();
                                                                          Mapper.Map(SalesOrderDTO, SalesOrder);
                                                                          //Untuk New entry dari transaksi bukan dari email
                                                                          if (String.IsNullOrEmpty(SalesOrder.SONo))
                                                                              SalesOrder.SONo = GetLastSONo(SalesOrderDTO.CostCenter, "SO");
                                                                          foreach (SalesOrderDetail salesOrderDetail in SalesOrder.SalesOrderDetails)
                                                                          {
                                                                              salesOrderDetail.SalesOrder = SalesOrder;
                                                                              salesOrderDetail.SalesOrderDetailId = 0;
                                                                          }
                                                                          SalesOrderRepository.SaveOrUpdate(SalesOrder);
                                                                          if (SalesOrder.PreSalesOrder != null)
                                                                          {
                                                                              PreSalesOrder presales =
                                                                                  _preSalesOrderRepository.GetDataOne(x => x.PSNo == SalesOrderDTO.PreSalesOrder.PSNo);
                                                                              if (presales != null)
                                                                              {
                                                                                  presales.Status = Convert.ToInt16(Status.Close);
                                                                                  _preSalesOrderRepository.SaveOrUpdate(presales);
                                                                              }
                                                                          }
                                                                      }
                                                                      else
                                                                      {

                                                                          if (SalesOrder.Status == (int)Status.Void || SalesOrder.Status == (int)Status.Close)
                                                                              throw new Exception("Tidak bisa di Update Status sudah Close atau Void!");
                                                                          SalesOrderRepository.Delete(SalesOrder);
                                                                          var SO = new SalesOrder();
                                                                          SO.modified_date = DateTime.Now;
                                                                          SO.created_date =
                                                                              SalesOrder.created_date;
                                                                          Mapper.Map(SalesOrderDTO, SO);
                                                                          foreach (var SalesOrderDetail in SO.SalesOrderDetails)
                                                                              SalesOrderDetail.SalesOrder = SO;
                                                                          SalesOrderRepository.Session.SaveOrUpdateCopy(SO);
                                                                          if (SO.PreSalesOrder != null)
                                                                          {
                                                                              PreSalesOrder presales =
                                                                                  _preSalesOrderRepository.GetDataOne(x => x.PSNo == SalesOrderDTO.PreSalesOrder.PSNo);
                                                                              presales.Status = Convert.ToInt16(Status.Close);
                                                                              _preSalesOrderRepository.SaveOrUpdate(presales);
                                                                          }

                                                                      }
                                                                  });
              
                res = true;
            }
            catch (Exception  ex)
            {
                throw ex;
            }

            return res;
        }


        public bool Delete(SalesOrderDTO SalesOrderDto)
        {
            bool res;
            try
            {
                SalesOrder SalesOrder = SalesOrderRepository.GetDataOne(x => x.SONo == SalesOrderDto.SONo);
                SalesOrder.Status = 2;
                SalesOrderRepository.SaveOrUpdate(SalesOrder);
                //Release PSO 
                if (SalesOrder.PreSalesOrder != null)
                {
                    var preSales= _preSalesOrderRepository.GetDataOne(ps => ps.PSNo == SalesOrder.PreSalesOrder.PSNo);
                    preSales.Status = (int)Status.Open;
                    _preSalesOrderRepository.SaveOrUpdate(preSales);
                }
                    
                   
                //SalesOrderRepository.Delete(SalesOrder);
                res = true;
            }
            catch (Exception)
            {
                res = false;
                throw;
            }

            return res;
        }


        public List<SalesOrderDTO> GetListByCriteria(Dictionary<String, Object> criteria, string expression, int page,
                                                     out long recordCount)
        {
            var SalesOrders = new List<SalesOrder>();
            var Results = new List<SalesOrderDTO>();
            SalesOrders = SalesOrderRepository.GetDataPaged(criteria, expression, page, 30).ToList();
            recordCount = SalesOrderRepository.RecordCount;
            SalesOrders.ForEach(x =>
                                    {
                                        SalesOrderDTO SalesOrderDto = x.ConvertToDTO<SalesOrder, SalesOrderDTO>();
                                        var SI = SIRepository.GetDataOne(d => d.DeliveryOrder.SalesOrder.SONo == x.SONo);
                                        var DO = DORepository.GetDataOne(d => d.SalesOrder.SONo == x.SONo);
                                        if (x.PreSalesOrder != null) SalesOrderDto.PSNo = x.PreSalesOrder.PSNo;
                                        if (SI != null) SalesOrderDto.SINo = SI.SINo;
                                        if (DO != null) SalesOrderDto.DONo = DO.DONo;
                                        SalesOrderDto.Status = (Status) x.Status;
                                        Results.Add(SalesOrderDto);
                                    });
            return Results;
        }


        public List<SalesOrderDTO> GetAllSalesOrder()
        {
            List<SalesOrder> SalesOrders =
                SalesOrderRepository.GetDataList(x => x.Status == Convert.ToInt16(Status.Open)).ToList();
            IEnumerable<SalesOrderDTO> Results = from s in SalesOrders
                                                 select new SalesOrderDTO {SONo = s.SONo};

            return Results.ToList();
        }


        public SalesOrderDTO GetSalesOrder(String soNo)
        {
            SalesOrder salesOrder = SalesOrderRepository.GetDataOne(x => x.SONo == soNo);
            var salesOrderDto = new SalesOrderDTO();
            salesOrderDto.InjectFrom<CloneInjection>(salesOrder);
            return salesOrderDto;
        }

        public List<SalesOrderDTO> GetSalesOrderList(string soNo)
        {
            List<SalesOrder> SalesOrders = SalesOrderRepository.GetDataList(x => x.SONo.Contains(soNo)).ToList();
            var Results = new List<SalesOrderDTO>();
            SalesOrders.ForEach(x =>
                                    {
                                        var salesOrderDto = new SalesOrderDTO();
                                        salesOrderDto.InjectFrom<CloneInjection>(x);
                                        Results.Add(salesOrderDto);
                                    }
                );

            return Results;
        }

        public string GetLastSONo(CostCenterDTO costCenter, string Tipe)
        {
            var appParamServices = new AppParamServices();
            AppParamDTO param = appParamServices.GetAppParamList("KodeSO").FirstOrDefault();
            string res = SalesOrderRepository.GetMaxNumber(costCenter.CostCenterId, Tipe,param.AppParamValue);

            if (string.IsNullOrEmpty(res))
                res = param.AppParamValue;

            string formatSO = "0000";
            string lastNo = string.Empty;
            string kodeSO;
            if (res.Length <= 4)
            {
                lastNo = formatSO;
                kodeSO = res;
            }
            else
            {
                lastNo = res.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[3];
                kodeSO = res.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[0];
            }
            string soNum = formatSO.Substring(0, formatSO.Length - (int.Parse(lastNo) + 1).ToString().Length) +
                           (int.Parse(lastNo) + 1);

            return kodeSO + "/" + costCenter.CostCenterId + "/" + DateTime.Now.Year + "/" + soNum;
        }

        public bool DeleteDetail(SalesOrderDetailDTO SalesOrderDetailDto)
        {
            bool res;
            try
            {
                var SODetail = SalesOrderRepository.Session.Get<SalesOrderDetail>(SalesOrderDetailDto.SalesOrderDetailId);
                SalesOrderRepository.DeleteDetail(SODetail, SalesOrderDetailDto.SalesOrderDetailId);
                res = true;
            }
            catch (Exception)
            {
                res = false;
            }

            return res;
        }

        public List<SalesOrderDTO> GetSalesOrderListByCostCenter(CostCenterDTO costCenterDto)
        {
            if (costCenterDto == null) return new List<SalesOrderDTO>();
            IList<SalesOrder> SalesOrders =
                SalesOrderRepository.GetDataList(
                    x =>
                    x.CostCenter.CostCenterId == costCenterDto.CostCenterId && x.Status == Convert.ToInt16(Status.Open));
            IEnumerable<SalesOrderDTO> Results = from s in SalesOrders
                                                 select new SalesOrderDTO {SONo = s.SONo,SODate = s.SODate};

            return Results.ToList();
        }

        public bool SendEmail(SalesOrderDTO obj, String DestinationFolder)
        {
            var mailServices = new MailServices();
            SalesOrder Obj = SalesOrderRepository.GetDataOne(x => x.SONo == obj.SONo);
            obj = Mapper.Map(Obj, obj);
            return mailServices.SendEmail(obj,DestinationFolder);
        }


        #endregion
    }
}